package edu.mama.college.service;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class RedisService {

    /**
     * Spring的缓存控制是作用在方法上的，其核心思想是这样的：当我们在调用一个缓存方法时会把该方法参数和返回值作为一个键值对存放在缓存中，等到下次利用同样的参数来调用该方法时将不再执行该方法，而是直接从缓存中获取结果进行返回。
     * Spring提供了几个注解来支持缓存，主要是 @Cacheable 和 @CacheEvict 。
     * 使用 @Cacheable 标记的方法执行完成后会缓存其返回值，
     * 而使用 @CacheEvict 标记的方法会在方法执行前或者执行后移除缓存中的某些元素。
     *
     * @Cacheable 可以标记在一个方法上，也可以标记在一个类上。
     * 当标记在一个方法上时表示该方法是支持缓存的，
     * 当标记在一个类上时则表示该类所有的方法都是支持缓存的。
     * 对于一个支持缓存的方法，Spring会在其被调用后将其返回值缓存起来，以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果，而不需要再次执行该方法。
     * 缓存是键值对的形式存储的，值就是方法的返回值，至于键，Spring支持两种策略，默认策略和自定义策略。
     *
     * 注意：
     * 1、返回值类型需要实现 java.io.Serializable 接口。
     * 2、在类的其它方法调用支持缓存的方法时，不会触发缓存功能。
     *
     *
     * @CachePut 也可以标注在类或方法上，声明一个方法支持缓存功能，用法跟 @Cacheable 相同，。
     * 使用 @Cacheable 标注的方法，Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素，如果存在就不再执行该方法，而是直接从缓存中获取结果进行返回，否则才会执行并将返回值存入指定的缓存中。
     * 不同的是，使用 @CachePut 标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果，而是每次都会执行该方法，并将执行结果以键值对的形式存入指定的缓存中。
     *
     *
     * @CacheEvict 是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。
     * 清除缓存操作默认是在对应方法成功执行之后触发的，即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间，当我们指定该属性值为true时，Spring会在调用该方法之前清除缓存中的指定元素。
     */


    @Cacheable("cache1")
    public String cache1(String arg) {
        System.out.println("cache1 arg = " + arg);
        return arg;
    }

    @Cacheable("cache2")
    public String cache2(String x, String m) {
        String xm = x + m;
        System.out.println("cache2 xm = " + xm);
        return xm;
    }

    /**
     * 自定义缓存key
     * 1、可用参数值作为key，用法：#参数名
     * 2、参数为对象时，可用对象的属性值作为key，用法：#参数名.属性
     * 3、可用多个参数拼接计算结果作为Key，用法：#参数名1 + '::' + #参数名2.属性
     */
    @Cacheable(value = "cache3", key = "#x")
    public String cache3(String x, String m) {
        String xm = x + m;
        System.out.println("cache3 xm = " + xm);
        return xm;
    }

    public String cache4(String arg) {
        return cache1(arg);
    }


    /**
     * 更新缓存，不指定key时采用默认策略。
     */
    @CachePut(value = "cache5", key = "#x")
    public String cache5(String x, String m) {
        String xm = x + m;
        System.out.println("cache5 xm = " + xm);
        return xm;
    }


    /**
     * 清除缓存，不指定key时采用默认策略。
     */
    @CacheEvict("cache1")
    public void evict1(String arg) {
        System.out.println("evict cache1 : arg = " + arg);
    }

    /**
     * 清除缓存，不指定key时采用默认策略，调用方法前清除缓存
     */
    @CacheEvict(value = "cache2", beforeInvocation = true)
    public void evict2(String x, String m) {
        System.out.println("evict cache2 : x=" + x + " m=" + m);
    }

}
